﻿using System;
using System.Linq;
using FarmerJoe.Helpers;
using FarmerJoe.Helpers.Logging;
using FarmerJoe.Helpers.Units;
using FarmerJoe.Settings;
using Styx;
using Styx.Common;
using Styx.CommonBot;
using Styx.CommonBot.POI;
using Styx.Pathing;
using Styx.TreeSharp;
using Styx.WoWInternals;

namespace FarmerJoe
{
    partial class Base
    {
        #region Base Composites
        private Composite _pullBehavior;
        private Composite _preCombatBuffsBehavior;
        private Composite _restBehavior;
        private Composite _healBehavior;
        #endregion

        #region Pulling
        public override Composite PullBehavior
        {
            get
            {
                if (_pullBehavior == null)
                {
                    Log.Write(LogLevel.Verbose, "Creating 'Pull' behavior");

                    _pullBehavior = CreatePullBehaviors();
                    if (_pullBehavior == null)
                    {
                        Log.Write("No pull routine is available for your class, " + Me.Class);
                    }
                }
                return _pullBehavior;
            }
        }

        private Composite CreatePullBehaviors()
        {
            switch (Me.Class)
            {
                case WoWClass.Druid:
                    return Classes.Druid.PullBehavior_SpecSwitch();

                case WoWClass.Priest:
                    return Classes.Priest.PullBehavior_SpecSwitch();

                case WoWClass.Warlock:
                    return Classes.Warlock.PullBehavior_SpecSwitch();

                case WoWClass.Hunter:
                    return Classes.Hunter.PullBehavior_SpecSwitch();


                default:
                    return null;
            }

        }
        #endregion

        #region Pre Combat Buffs
        public override Composite PreCombatBuffBehavior
        {
            get
            {
                if (_preCombatBuffsBehavior == null)
                {
                    Log.Write(LogLevel.Verbose, "Creating 'PreCombatBuffs' behavior");

                    _preCombatBuffsBehavior = CreatePreCombatBuffsBehaviors();
                    if (_preCombatBuffsBehavior == null)
                    {
                        Log.Write("No precombat buff routine is available for your class, " + Me.Class);
                    }
                }
                return _preCombatBuffsBehavior;
            }
        }

        private Composite CreatePreCombatBuffsBehaviors()
        {
            switch (Me.Class)
            {
                case WoWClass.Druid:
                    return Classes.Druid.PreCombatBuffs();

                case WoWClass.Priest:
                    return Classes.Priest.PreCombatBuffs();

                case WoWClass.Warlock:
                    return Classes.Warlock.PreCombatBuffs();

                case WoWClass.Hunter:
                    return Classes.Hunter.PreCombatBuffs();


                default:
                    return null;
            }

        }
        #endregion

        #region Heal

        private int _healCheckCount = 0;
        public override Composite HealBehavior
        {
            get
            {
                if (_healBehavior == null)
                {
                    if (_healCheckCount <= 0)
                    Log.Write(LogLevel.Verbose, "Creating 'Heal' behavior");

                    _healBehavior = HealBehaviors();
                    if (_restBehavior == null)
                    {
                        if (_healCheckCount <= 0)
                        Log.Write("No healing routine is available for your class, " + Me.Class);
                    }
                }

                _healCheckCount += 1;
                return _healBehavior;
            }
        }

        private Composite HealBehaviors()
        {
            switch (Me.Class)
            {
                case WoWClass.Druid:
                    return Me.Specialization == WoWSpec.DruidRestoration ? Classes.Druid.Behaviour_Restoration(ClassParser.CCControlledMovement) : null;

                case WoWClass.Hunter:
                    //return Classes.Hunter.PetLoot();

                case WoWClass.Monk:
                case WoWClass.Paladin:
                
                case WoWClass.Rogue:
                case WoWClass.Warrior:
                case WoWClass.Shaman:
                case WoWClass.Mage:
                case WoWClass.DeathKnight:
                case WoWClass.Warlock:
                    return null;
//                    return Classes.Common.RestBehaviour();

                case WoWClass.Priest:
                    return Me.Specialization == WoWSpec.PriestDiscipline ? Classes.Priest.CombatBehaviour_Discipline(ClassParser.CCControlledMovement) : null;


            }


            return null;
        }
        #endregion

        #region Rest
        public override Composite RestBehavior
        {
            get
            {
                if (_restBehavior == null)
                {
                    Log.Write(LogLevel.Verbose, "Creating 'Rest' behavior");

                    _restBehavior = RestBehaviors();
                    if (_restBehavior == null)
                    {
                        Log.Write("No rest routine is available for your class, " + Me.Class);
                    }
                }
                return _restBehavior;
            }
        }

        private Composite RestBehaviors()
        {
            switch (Me.Class)
            {
                case WoWClass.Druid:
                    //Log.Write("=== in rest");
                    return Me.Specialization == WoWSpec.DruidRestoration ? Classes.Druid.Behaviour_Restoration(ClassParser.CCControlledMovement) : Classes.Common.RestBehaviour();

                case WoWClass.Priest:
                    //Log.Write("=== in rest");
                    return Me.Specialization == WoWSpec.PriestDiscipline ? Classes.Priest.CombatBehaviour_Discipline(ClassParser.CCControlledMovement) : Classes.Common.RestBehaviour();

                case WoWClass.Warlock:
                    return Classes.Warlock.AllFormsRest();

                case WoWClass.Hunter:
                    return Classes.Hunter.AllFormsRest();

                case WoWClass.Monk:
                case WoWClass.Paladin:
                case WoWClass.Rogue:
                case WoWClass.Warrior:
                case WoWClass.Shaman:
                case WoWClass.Mage:
                case WoWClass.DeathKnight:
                
                    return Classes.Common.RestBehaviour();
            }
            

            return null;
        }
        #endregion

        private bool BotPoiCanSpeedUp
        {
            get
            {
                return (

                    BotPoi.Current.Type == PoiType.Quest || 
                    BotPoi.Current.Type == PoiType.Skin || 
                    BotPoi.Current.Type == PoiType.Loot || 
                    BotPoi.Current.Type == PoiType.InnKeeper || 
                    BotPoi.Current.Type == PoiType.Hotspot || 
                    BotPoi.Current.Type == PoiType.Buy || 


                    BotPoi.Current.Type == PoiType.Mail || 
                    BotPoi.Current.Type == PoiType.QuestTurnIn ||
                    BotPoi.Current.Type == PoiType.QuestPickUp || 
                    BotPoi.Current.Type == PoiType.Repair ||
                    BotPoi.Current.Type == PoiType.Sell || 
                    BotPoi.Current.Type == PoiType.Train ||
                    BotPoi.Current.Type == PoiType.Harvest);
            }
        }
        public override void Pulse()
        {
            
            if (!StyxWoW.IsInGame || !StyxWoW.IsInWorld) return;

            if (Healing.NeedHealTargeting)  Healing.Instance.Pulse();
            if (Group.MeIsTank && (Me.GroupInfo.IsInParty || Me.GroupInfo.IsInRaid)) Tanking.Instance.Pulse();

            if (Me.Class == WoWClass.Druid)
            {
               
                if (FpswareSettings.Instance.Druid.TravelForm.Contains("always"))
                    if (Me.Shapeshift != ShapeshiftForm.Travel && Me.Shapeshift != ShapeshiftForm.Aqua && !Battlegrounds.IsInsideBattleground && !Me.InVehicle)
                    {
                        if (!Me.Mounted && !Me.Combat && (Timers.AutoExpire("Travel Form", 1000) && SpellManager.HasSpell("Travel Form")))
                        {
                            int countOfMobsAroundUs = Me.HostileUnitsNearTarget(25).Count();
                            if (BotPoiCanSpeedUp && countOfMobsAroundUs == 0)
                            {
                                int minDistance = Convert.ToInt32(FpswareSettings.Instance.Druid.TravelFormMinDistance);
                                if (BotPoi.Current.Location.Distance(Me.Location) >= minDistance && BotPoi.Current.Location.Distance(Me.Location) < 100f)
                                {
                                    SpellManager.Cast(Me.IsSwimming ? "Aquatic Form" : "Travel Form");
                                }
                            }
                        }
                    }

            }


            if (Me.Class == WoWClass.Warlock)
            {
                if (Me.Mounted || Me.IsFlying || Me.InVehicle)
                {
                    Timers.Reset("Summon Pet");
                }

                if (Me.HasAura("Burning Rush") && (Me.Combat || Me.HealthPercent < 60 || !BotPoiCanSpeedUp))
                {
                    Lua.DoString("CancelUnitBuff('player', 'Burning Rush')");
                }

                if (!Me.Combat && Me.HasAura("Metamorphosis") && !Me.HasAura("Dark Soul: Knowledge"))
                {
                    Lua.DoString("CancelUnitBuff('player', 'Metamorphosis')");
                }

                if (!Me.Mounted && !Me.HasAura("Burning Rush") && (Timers.SpellOkToCast("Burning Rush", 4000) && SpellManager.HasSpell("Burning Rush")))
                    if (Me.HealthPercent > 60)
                        if (BotPoiCanSpeedUp)
                            if (BotPoi.Current.Location.Distance(Me.Location) > 20 && BotPoi.Current.Location.Distance(Me.Location) < 100)
                            {
                                SpellManager.Cast("Burning Rush");
                            }

            }


            if (Me.Class == WoWClass.Hunter)
            {
                if (Me.Mounted || Me.IsFlying || Me.InVehicle)
                {
                    Timers.Reset("Summon Pet");
                }

                // Cancel AotC if hostile mobs are near by
                float cancelCheetahRange = TalentsAndGlyphs.HasGlyph("Aspect of the Cheetah") ? 10f : 25f;
                if (Me.HasAura("Aspect of the Cheetah") && (Me.Combat || Me.HostileUnitsNearTarget(cancelCheetahRange).Any()) || Me.Mounted || Me.IsFlying)
                {
                    Lua.DoString("CancelUnitBuff('player', 'Aspect of the Cheetah')");
                }

                // Focus Fire, use it or loose it.
                if (!Me.Mounted && !Me.IsFlying && !Me.InVehicle)
                {
                    if (!Me.IsCasting && !Me.IsChanneling)
                        if (Me.HasAura("Frenzy") && !Me.HasAura("Focus Fire") && Me.Auras["Frenzy"].StackCount >= 2 && Me.AuraTimeLeft("Frenzy") <= 3 && SpellManager.CanCast("Focus Fire"))
                            SpellManager.Cast("Focus Fire");
                }


                // Use AotC, unless we're in a Battlegrounds
                if (FpswareSettings.Instance.Hunter.AspectOfTheCheetah.Contains("always"))
                    if (!Me.HasAura("Aspect of the Cheetah") && !Battlegrounds.IsInsideBattleground && !Me.IsSwimming && !Me.InVehicle)
                    {
                        if (!Me.Mounted && !Me.Combat && (Timers.AutoExpire("Aspect of the Cheetah", 1000) && SpellManager.HasSpell("Aspect of the Cheetah")))
                        {
                            int countOfMobsAroundUs = Me.HostileUnitsNearTarget(cancelCheetahRange).Count();
                            if (BotPoiCanSpeedUp && countOfMobsAroundUs == 0)
                            {
                                int minDistance = Convert.ToInt32(FpswareSettings.Instance.Hunter.AspectOfTheCheetahMinDistance);
                                if (BotPoi.Current.Location.Distance(Me.Location) >= minDistance && BotPoi.Current.Location.Distance(Me.Location) < 100f) 
                                {
                                    SpellManager.Cast("Aspect of the Cheetah");
                                }
                            }
                        }
                    }

                // Got a Sea Strider? And we're swimming?
                if (!Me.Combat && !Me.IsFlying && !Me.InVehicle && Me.GotAlivePet && Me.IsSwimming && Me.Pet.Name.Contains("Strider") && Timers.AutoExpire("Water Walking",1000))
                {
                    if (!Me.HasAura("Surface Trot"))
                    {
                        Log.Write(Colours.InformativeColour, "Oh it looks like we can use water walking...");
                        Log.Write(Colours.InformativeColour,"... and we have a water strider as our pet");
                        //Movement.EnsureMovementStopped();
                        //Mount.Dismount();

                        if (Pets.CanCastPetAction("Surface Trot"))
                        {
                            Movement.EnsureMovementStopped();
                            Mount.Dismount();
                            Movement.EnsureMovementStopped();
                            
                            Log.Write(Colours.InformativeColour, "Casting Surface Trot on Player");
                            Pets.CastPetAction("Surface Trot", Me);
                        }
                    }

                    if (Me.HasAura("Surface Trot"))
                    {
                        //Movement.EnsureMovementStopped();
                        //Mount.Dismount();
                        //Movement.EnsureMovementStopped();
                        Log.Write(Colours.InformativeColour, "We have a water walk buff but we're still swimming. Jump out of the water");
                        WoWMovement.Move(WoWMovement.MovementDirection.JumpAscend,new TimeSpan(0,0,0,3));

                    }

                }

            }

            base.Pulse();

        }
    }
}
